package com.aifast.common.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.aifast.common.global.BusinessException;
import com.aifast.common.global.Const;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 常用的业务工具
 */
public class AiUtil {

    private final static Logger logger = LoggerFactory.getLogger(AiUtil.class);
    private static final String TTCC = "天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔龙师火帝鸟官人皇始制文字乃服衣裳推位让国有虞陶唐吊民伐罪周发殷汤坐朝问道垂拱平章爱育黎首臣伏戎羌遐迩一体率宾归王鸣凤在竹白驹食场化被草木赖及万方盖此身发四大五常恭惟鞠养岂敢毁伤女慕贞洁男效才良知过必改得能莫忘罔谈彼短靡恃己长信使可覆器欲难量墨悲丝染诗赞羔羊景行维贤克念作圣德建名立形端表正空谷传声虚堂习听祸因恶积福缘善庆尺璧非宝寸阴是竞资父事君曰严与敬孝当竭力忠则尽命临深履薄夙兴温凊似兰斯馨如松之盛川流不息渊澄取映容止若思言辞安定笃初诚美慎终宜令荣业所基籍甚无竟学优登仕摄职从政存以甘棠去而益咏乐殊贵贱礼别尊卑上和下睦夫唱妇随外受傅训入奉母仪诸姑伯叔犹子比儿孔怀兄弟同气连枝交友投分切磨箴规仁慈隐恻造次弗离节义廉退颠沛匪亏性静情逸心动神疲守真志满逐物意移坚持雅操好爵自縻都邑华夏东西二京背邙面洛浮渭据泾宫殿盘郁楼观飞惊图写禽兽画彩仙灵丙舍旁启甲帐对楹肆筵设席鼓瑟吹笙升阶纳陛弁转疑星右通广内左达承明既集坟典亦聚群英杜稿钟隶漆书壁经府罗将相路侠槐卿户封八县家给千兵高冠陪辇驱毂振缨世禄侈富车驾肥轻策功茂实勒碑刻铭磻溪伊尹佐时阿衡奄宅曲阜微旦孰营桓公匡合济弱扶倾绮回汉惠说感武丁俊义密勿多士实宁晋楚更霸赵魏困横假途灭虢践土会盟何遵约法韩弊烦刑起翦颇牧用军最精宣威沙漠驰誉丹青九州禹迹百郡秦并岳宗泰岱禅主云亭雁门紫塞鸡田赤城昆池碣石钜野洞庭旷远绵邈岩岫杳冥治本于农务兹稼穑俶载南亩我艺黍稷税熟贡新劝赏黜陟孟轲敦素史鱼秉直庶几中庸劳谦谨敕聆音察理鉴貌辨色贻厥嘉猷勉其祗植省躬讥诫宠增抗极殆辱近耻林皋幸即两疏见机解组谁逼索居闲处沉默寂寥求古寻论散虑逍遥欣奏累遣戚谢欢招渠荷的历园莽抽条枇杷晚翠梧桐蚤凋陈根委翳落叶飘摇游鹍独运凌摩绛霄耽读玩市寓目囊箱易輶攸畏属耳垣墙具膳餐饭适口充肠饱饫烹宰饥厌糟糠亲戚故旧老少异粮妾御绩纺侍巾帷房纨扇圆洁银烛炜煌昼眠夕寐蓝笋象床弦歌酒宴接杯举觞矫手顿足悦豫且康嫡后嗣续祭祀烝尝稽颡再拜悚惧恐惶笺牒简要顾答审详骸垢想浴执热愿凉驴骡犊特骇跃超骧诛斩贼盗捕获叛亡布射僚丸嵇琴阮啸恬笔伦纸钧巧任钓释纷利俗并皆佳妙毛施淑姿工颦妍笑年矢每催曦晖朗曜璇玑悬斡晦魄环照指薪修祜永绥吉劭矩步引领俯仰廊庙束带矜庄徘徊瞻眺孤陋寡闻愚蒙等诮谓语助者焉哉乎也";

    /**
     * 旺季 月份集合
     */
    private static final Integer[] HIGH_SEASON = {10,11,12,1,2,3};
    /**
     * 淡季 月份集合
     */
    private static final Integer[] LOW_SEASON = {4,5,6,7,8,9};


    /**
     * 生成用户搜索值 key
     */
    public static String generatorSearchKey(String username ,String mobile ,String realName){
//        String result = StrUtil.emptyToDefault(username,Const.EMPTY)
//                + generatorMobile(mobile)
//                + StrUtil.emptyToDefault(realName,Const.EMPTY);
        String result = StrUtil.join("-",StrUtil.emptyToDefault(username, Const.EMPTY),generatorMobile(mobile),StrUtil.emptyToDefault(realName,Const.EMPTY));
        return result;
    }

    public static String generatorMobile(String mobile){
        if(StrUtil.isNullOrUndefined(mobile) || StrUtil.isBlank(mobile)){
            return Const.EMPTY;
        }
        return mobile.substring(0,3) + mobile.substring(mobile.length() - 4,mobile.length());
    }

    /**
     * 判断整型id字段是否为空或者0
     * @param id
     * @return 错误返回false 正确返回true
     */
    public static boolean checkId(Integer id){
        if(Objects.equals(0,id) || Objects.equals(null, id)){
            return false;
        }
        return true;
    }

    /**
     * 判断整型id字段是否为空或者0
     * @param ids
     * @return 错误返回false 正确返回true
     */
    public static boolean checkId(Integer... ids){
        for(Integer i : ids){
            if(Objects.equals(0,i) || Objects.equals(null, i)){
                return false;
            }
        }

        return true;
    }

    /**
     * 判断集合是否为null 或者长度为0
     * @param collection
     * @return 错误返回false 正确返回true
     */
    public static boolean checkArray(Collection collection){
        if(null == collection || collection .size() == 0){
            return false;
        }
        return true;
    }

    /**
     * 隐藏手机号码中间四位
     * @param mobile
     * @return
     */
    public static String hideMobile(String mobile){
        if(StrUtil.isBlank(mobile) && mobile.length() != 11){
            return Const.EMPTY;
        }
        String s = mobile.substring(0,3) + Const.SYMBOL_MOBILE + mobile.substring(7);
        return s;
    }

    /**
     * 根据手机查询归属地 返回所有信息
     * @param mobile
     * @return
     */


    /**
     * 判断今日是否是本月最后一天
     * @return
     */
    public static boolean isEndOfMonth(){
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.DATE) == calendar.getActualMaximum(Calendar.DATE);
    }

    /**
     * 自动生成smart-doc的api文档
     */


    /**
     * 自动生成数据库文档
     */

    public static void main(String[] args) {
    }

    /**
     * 去除特殊字符
     * @param s 字符
     * @return
     */
    public static String removeExceptionSymbol(String s) {
        return s.replaceAll("\\s*","");

    }

    /**
     * 根据时间范围获取开始和截止时间 过往时间
     * @param offset 月份偏移量
     * @return 时间字符串数组
     */
    public static String[] getBeginAndEndDateByDateRange(Integer offset){
        Date now = new Date();
        DateTime tmp = DateUtil.offset(now, DateField.MONTH, - (offset - 1));
        String beginDate = DateUtil.beginOfMonth(tmp).toString("yyyy-MM-dd");
        String endDate = DateUtil.endOfMonth(now).toString("yyyy-MM-dd");
        String[] res = new String[2];
        res[0] = beginDate;
        res[1] = endDate;
        return res;
    }

    /**
     * 根据时间范围字符串拆分获取开始和截止时间
     * @param date 时间范围 如 2020-11-21 - 2020-11-22
     * @return
     */
    public static String[] getBeginAndEndDateByStr(String date){
        String[] tmp = new String[2];
        tmp[0] = date.substring(0,10);
        tmp[1] = date.substring(13);
        return tmp;
    }

    /**
     * 是否是生产环境
     * @return true 是 false 否 （为测试或开发环境）
     */
    public static boolean isProductionEnvironment(){
        String activeProfile = SpringUtil.getActiveProfile();
//        return StrUtil.equals("dev",activeProfile);
        return StrUtil.equals(Const.ACTIVE_PROFILE_CAT,activeProfile);
    }


    /**
     * 判断当前用户是否拥有某个权限标识
     * @param perm 权限标识
     * @return true 有 false 没有
     */
    public static boolean hasPermission(String perm){
        try {
            Object authService = SpringUtil.getBean(Const.SHIROUTIL);
            Object getAuthenticationInformation = ReflectUtil.invoke(authService, "getPermissions");
            if(Objects.equals(null,getAuthenticationInformation)){
                return false;
            }
            String[] strings = Convert.toStrArray(getAuthenticationInformation);
            return Arrays.asList(strings).contains(perm);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 是否是windows系统
     * @return 是true 否false
     */
    public static boolean isWindows(){
        return Const.OS_NAME.contains("windows");
    }

    /**
     * 是否是linux系统
     * @return 是true 否false
     */
    public static boolean isLinux(){
        return Const.OS_NAME.contains("linux");
    }

    /**
     * 自动化渲染操作系统路径
     * @param pathName 路径名称
     * @return 格式化的路径
     */
    public static String autoPath(String... pathName){
        String res = null;
        if(isWindows()){
            res = StrUtil.join("\\","",pathName,"");
        }else if(isLinux()){
            res = StrUtil.join("/","",pathName,"");
        }
        return res;
    }

    /**
     * 获取当天剩余时间
     * @return 秒
     */
    public static Long getTimeRemainingThisDay() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000;
    }

    /**
     * 获取某月的佣金系统时间日期算法(取时间参数所在月份的前一个月最后一天，到时间参数所在月份的倒数第二天
     * @param date 时间参数
     * @return [开始时间日期，结束时间日期]  数组
     */
    public static String[] getDateByCommission(Date date) {
        String[] beginAndEnd=new String[2];
         beginAndEnd[0]=DateUtil.format(DateUtil.offsetDay(DateUtil.beginOfMonth(date),-1),
                "yyyy-MM-dd");
        beginAndEnd[1]=DateUtil.format(DateUtil.offsetDay(DateUtil.endOfMonth(date),-1),
                "yyyy-MM-dd");
        return beginAndEnd;
    }

    /**
     * 按公司行业规定 根据时间字符串判断该时间是否是 旺季
     * @param date 时间 2021-01-09
     * @return 旺季 返回true 淡季 返回false
     */
    public static boolean isHighSeason(String date){
        int month = DateUtil.month(DateUtil.parseDate(date)) + 1;
        return Convert.toList(HIGH_SEASON).contains(month);
    }

    /**
     * 分割一定数量进行分割
     * @param count 总数
     * @param splitNum 按某个数值分割
     * @return 总共又多少个
     */
    public static Integer splitNum(Integer count,Integer splitNum) {
        return Convert.toInt(Math.ceil(Convert.toDouble(count)/splitNum));
    }

    /**
     * 获取主机IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取ip地址归属地
     * @param ip
     * @return
     */
    public static String getIpAddrHome(String ip){
        try {
            DbSearcher searcher = new DbSearcher(new DbConfig(), StrUtil.join("", Const.CURRTPATH,"ip2region/ip2region.db"));
            DataBlock dataBlock = searcher.binarySearch(ip);
            String region = dataBlock.getRegion();
            region.replaceAll("|0","");
            region.replaceAll("|"," ");
            return region;
        }catch (Exception e){
            return "IP地址分析错误...";
        }
    }

    /**
     * 返回流信息
     * @param response 返回流
     * @param json 返回信息
     * @throws Exception
     */
    public static void writeReturnJson(HttpServletResponse response, String json) throws Exception{
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);

        } catch (IOException e) {
        } finally {
            if (ObjectUtil.isNotNull(writer))
                writer.close();
        }
    }

    /**
     * 无权限url集合
     * @return
     */
    public static List<String> getExcludePathPatterns(){
        List<String> list = new ArrayList<>();
        list.add("/static/**");
        list.add("/pictures/**");
        list.add("/");
        list.add("/view/**");
        list.add("/favicon.ico");
        list.add("/login/**");
        list.add("/example/**");
        list.add("/aiim/**");
        list.add("/sse/**");
        list.add("/bucket/**");
        list.add("/sys/file/download");
        list.add("/doLoginById");
        list.add("/gen/genTable/download");
        list.add("/gen/genTable/genCode");
        list.add("/sys/words/export");
        list.add("/crm/customer/test");
        list.add("/flow/**");
        list.add("/json/**");
        list.add("/doc/**");
        return list;
    }

    /**
     * 用于代码抛出异常提示封装
     *
     * @param msg
     */
    public static void alert(String msg) {
        throw new BusinessException(msg);
    }

    public static Page getExportPage() {
        return new Page(0,100000);
    }

    /**
     * 一键生成数据库表的模拟数据
     * @param entity 实体模型
     * @param dataNum 数据条数
     * @param ignore 忽略的字段
     */
    public static void genAnalogData(Class<?> entity,int dataNum,String... ignore){
        Field[] fields1 = entity.getDeclaredFields();
        Field[] fields2 = entity.getSuperclass().getDeclaredFields();
        List<Field> fields = new ArrayList<>();
        fields.addAll(Arrays.asList(fields1));
        fields.addAll(Arrays.asList(fields2));
        for (int j = 0; j < dataNum; j++) {
            Record env = new Record();
            fields.forEach(i -> {
//            Console.log("字段类型：" + i.getType().getSimpleName() + " || 字段名：" + i.getName());
                if(ObjectUtil.isNotNull(ignore) && ignore.length >0 && Arrays.asList(ignore).contains(i.getName())){
                    return;
                }
                TableField annotation = i.getAnnotation(TableField.class);
                if(ObjectUtil.isNotNull(annotation) && !annotation.exist()){
                    return;
                }
                String name = StrUtil.toUnderlineCase(i.getName());
                if (StrUtil.equals("serialVersionUID", name) || StrUtil.equals("id",name)) {
                    return;
                }
                if (StrUtil.equals("user_id", name) ) {
                    env.set(name,392);
                    return;
                }
                if (StrUtil.equals("org_id", name)) {
                    env.set(name,2);
                    return;
                }
                if (StrUtil.equals("create_time", name) || StrUtil.equals("update_time", name)) {
                    env.set(name, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    return;
                }
                if(StrUtil.equals("create_by",name) || StrUtil.equals("update_by",name)){
                    env.set(name,"李淳罡");
                    return;
                }
                if(StrUtil.equals("String",i.getType().getSimpleName())){
//                    String join = StrUtil.join("", RandomUtil.randomChinese(), RandomUtil.randomChinese(), RandomUtil.randomChinese());
                    int index = RandomUtil.randomInt(1000);
                    String substring = index > 3 ? TTCC.substring(index - 3, index) : TTCC.substring(index, index + 3);
                    env.set(name,substring);
                    return;
                }
                if(StrUtil.equals("Integer",i.getType().getSimpleName())){
                    int randomInt = RandomUtil.randomInt(0, 3);
                    env.set(name,randomInt);
                    return;
                }

                if(StrUtil.equals("BigDecimal",i.getType().getSimpleName())){
                    BigDecimal decimal = RandomUtil.randomBigDecimal();
                    env.set(name,decimal);
                    return;
                }
            });

            String tableName = StrUtil.toUnderlineCase(entity.getSimpleName());
//            Console.log(env);
            Db.save(tableName,env);
        }
    }
}
